package HashMap.Nodo.Operaciones;

import HashMap.GenerarCodigoNASM;
import HashMap.Nodo.Categoria;
import HashMap.Nodo.Clase;
import HashMap.Nodo.Nodo;
import HashMap.Nodo.Operacion;
import HashMap.Nodo.Subclases.Conjunto;
import HashMap.Nodo.Subclases.Escalar;
import HashMap.Nodo.TipoBasicoDeDatos;
import HashMap.Pila;

public class OperacionesDeConjuntos implements Operacion {

    private Conjunto conjunto1;
    private Conjunto conjunto2;
    private Conjunto conjunto3;
    private Nodo nodo1;
    private Nodo nodo2;
    private Nodo nodoFinal;
    private String operacion;

    public OperacionesDeConjuntos(Nodo nodo1, Nodo nodo2, Nodo nodo3, String operacion) {
        switch (operacion) {
            case "UNION":
                if (nodo1.getClase() == Clase.CONJUNTO
                        && nodo2.getClase() == Clase.CONJUNTO
                        && nodo3.getClase() == Clase.CONJUNTO) {
                    Conjunto conjunto1 = (Conjunto) nodo1;
                    Conjunto conjunto2 = (Conjunto) nodo2;
                    Conjunto conjunto3 = (Conjunto) nodo3;
                    if (conjunto1.getCapacidad() >= conjunto2.getCapacidad() + conjunto3.getCapacidad()) {
                        this.conjunto1 = (Conjunto) nodo1;
                        this.conjunto2 = (Conjunto) nodo2;
                        this.conjunto3 = (Conjunto) nodo3;
                    } else {
                        throw new IllegalArgumentException("Las conjuntos tienen que rener tamaños correctos");
                    }
                }
            case "INTERSECCION":
                if (nodo1.getClase() == Clase.CONJUNTO
                        && nodo2.getClase() == Clase.CONJUNTO
                        && nodo3.getClase() == Clase.CONJUNTO) {
                    Conjunto conjunto1 = (Conjunto) nodo1;
                    Conjunto conjunto2 = (Conjunto) nodo2;
                    Conjunto conjunto3 = (Conjunto) nodo3;
                    if (conjunto1.getCapacidad() >= conjunto2.getCapacidad()
                            || conjunto1.getCapacidad() >= conjunto3.getCapacidad()) {
                        this.conjunto1 = (Conjunto) nodo1;
                        this.conjunto2 = (Conjunto) nodo2;
                        this.conjunto3 = (Conjunto) nodo3;
                    } else {
                        throw new IllegalArgumentException("Las conjuntos tienen que rener tamaños correctos");
                    }
                }
            case "ADD":
                if (nodo1.getClase() == Clase.CONJUNTO
                        && nodo2.getClase() == Clase.ESCALAR
                        && (nodo2.getNivelDeIndireccion() == 0
                        || nodo2.getNivelDeIndireccion() == 1)) {
                    this.conjunto1 = (Conjunto) nodo1;
                    this.nodo1 = nodo2;
                } else {
                    throw new IllegalArgumentException("Las conjuntos tienen que rener tamaños correctos");

                }
            case "CLEAR":
                if (nodo1.getClase() == Clase.CONJUNTO) {
                    this.conjunto1 = (Conjunto) nodo1;
                } else {
                    throw new IllegalArgumentException("Las conjuntos tienen que rener tamaños correctos");
                }
            case "SIZE":
                if (nodo1.getClase() == Clase.CONJUNTO) {
                    this.nodo1 = nodo1;
                } else {
                    throw new IllegalArgumentException("Las expresiones tienen que ser"
                            + " numericas y con nivel de indireccion 0 o 1");
                }
            case "CONTAINS":
                if ((nodo1.getTipoBasicoDeDatos() == TipoBasicoDeDatos.INT)
                        && (nodo1.getNivelDeIndireccion() == 0
                        || nodo1.getNivelDeIndireccion() == 1)
                        && (nodo2.getClase() == Clase.CONJUNTO)) {
                    this.nodo1 = nodo1;
                    this.nodo2 = nodo2;
                } else {
                    throw new IllegalArgumentException("Las expresiones tienen que ser"
                            + " numericas y con nivel de indireccion 0 o 1");
                }
        }
    }

    @Override
    public int getLongitud() {
        throw new UnsupportedOperationException("Operacion no soportada");
    }

    @Override
    public String generarCodigoNASM() {
        switch (nodo1.getOperacion()) {
            case "UNION":
                return generarCodigoNASMunion();
            case "INTERSECTION":
                return generarCodigoNASMinterseccion();
            case "ADD":
                return generarCodigoNASMinserccion();
            case "CLEAR":
                return generarCodigoNASMvaciado();
            case "SIZE":
                return generarCodigoNASMtamanho();
            case "CONTAINS":
                return generarCodigoNASMpertenencia();
            default:
                return null;
        }
    }

    @Override
    public Nodo generarNodo(String tokenOperacion) {
        switch (tokenOperacion) {
            case "UNION":
                return union();
            case "INTERSECTION":
                return interseccion();
            case "ADD":
                return inserccion();
            case "CLEAR":
                return vaciado();
            case "SIZE":
                return tamanho();
            case "CONTAINS":
                return pertenencia();
            default:
                return null;
        }
    }

    private Nodo union() {
        return null;
    }

    private Nodo interseccion() {
        return null;
    }

    private Nodo inserccion() {
        return null;
    }

    private Nodo vaciado() {
        return null;
    }

    private Nodo tamanho() {
        GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
        String nombre = generador.getNombreVariableAuxiliar();
        nodoFinal = new Escalar(nombre, TipoBasicoDeDatos.INT, Categoria.VARIABLE, 0, operacion);
        Pila.getInstancia().addNodoALaTablaSuperior(nodoFinal);
        return nodoFinal;
    }

    private Nodo pertenencia() {
        GenerarCodigoNASM generador = GenerarCodigoNASM.getInstancia();
        String nombre = generador.getNombreVariableAuxiliar();
        Nodo nodo = new Escalar(nombre, TipoBasicoDeDatos.BOOLEAN, Categoria.VARIABLE, 0, operacion);
        Pila.getInstancia().addNodoALaTablaSuperior(nodo);
        return nodo;
    }

    private String generarCodigoNASMunion() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private String generarCodigoNASMinterseccion() {
        return "ints [" + nodo1.getNombre() + "], [" + nodo2.getNombre() + "]\n"
                + "mov [" + nodoFinal.getNombre() + "], aux";
    }

    private String generarCodigoNASMinserccion() {
        return "add [" + nodo1.getNombre() + "], [" + nodo2.getNombre() + "]";
    }

    private String generarCodigoNASMvaciado() {
        return "call clear [" + nodo1.getNombre() + "]";
    }

    private String generarCodigoNASMtamanho() {
        return "siz [" + nodoFinal.getNombre() + "], [" + nodo1.getNombre() + "]";
    }

    private String generarCodigoNASMpertenencia() {
        return "cnts [" + nodo1.getNombre() + "], [" + nodo2.getNombre() + "]\n"
                + "mov [" + nodoFinal.getNombre() + "], aux";
    }
}
